package com.htfyun.eink.pw.draw.pen.epd;

import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.htfyun.eink.pw.configs.PWConfig;
import com.htfyun.eink.pw.core.ctrl.PWCoreHelper;
import com.htfyun.eink.pw.draw.IPWDrawPath;
import com.htfyun.eink.pw.draw.cache.IPathCache;
import com.htfyun.eink.pw.draw.pen.IPenWriter;
import com.htfyun.eink.pw.draw.pen.PenDrawPointerResultEnums;
import com.htfyun.eink.pw.draw.pen.epd.data.NeoRenderPoint;
import com.htfyun.eink.pw.draw.pointer.PWPointer;
import com.htfyun.eink.pw.draw.pointer.PWPointerActionEnums;

import java.util.List;

public abstract class PenEPDBase implements IPenWriter {
    protected final Rect rectOfUpdatePW = new Rect();

    private final EPDBaseManager manager;

    private int lastPointIndex = 0;

    protected final Paint paintRandom = new Paint();

    protected PenEPDBase(EPDBaseManager epdBase) {
        this.manager = epdBase;
    }

    @NonNull
    @Override
    public PenDrawPointerResultEnums drawPointer(@NonNull IPWDrawPath draw, @NonNull PWPointer pwPointer) {
        manager.setStrokeWidth(draw.getPaintConfig().strokeWidth);

        PWPointer pointer = new PWPointer(pwPointer);
        PWPointerActionEnums actionEnums = pointer.toPWPointerActionEnums();

        switch (actionEnums) {
            case DOWN:
                manager.onDown(pointer);
                break;
            case MOVE:
                manager.onMove(pointer);
                break;
            case UP:
                manager.onUp(pointer);
            default:
                break;
        }

        PenDrawPointerResultEnums resultEnums = handle(draw);

        if (actionEnums == PWPointerActionEnums.UP) {
            manager.clear();
            lastPointIndex = 0;
        }
        return resultEnums;
    }

    private PenDrawPointerResultEnums handle(@NonNull IPWDrawPath draw) {
        List<NeoRenderPoint> renderPoints = manager.getRenderPoints();
        if (renderPoints.size() == 0 || lastPointIndex >= renderPoints.size()) {
            return PenDrawPointerResultEnums.NONE;
        }

        NeoRenderPoint lastPoint = renderPoints.get(lastPointIndex);

        float lastX = lastPoint.x;
        float lastY = lastPoint.y;

        draw.getPaintConfig().configPaint(paintRandom);
        for (int index = lastPointIndex; index < renderPoints.size(); index++) {
            NeoRenderPoint pointer = renderPoints.get(index);
            float x = pointer.x;
            float y = pointer.y;

            Path pathOfUpdatePW = new Path();
            pathOfUpdatePW.moveTo(lastX, lastY);
            pathOfUpdatePW.quadTo((lastX + x) / 2.0f, (lastY + y) / 2.0f, x, y);

            paintRandom.setStrokeWidth(pointer.size);
            draw.drawPath(pathOfUpdatePW, paintRandom, rectOfUpdatePW);

            PWCoreHelper.postRectForPw(rectOfUpdatePW,
                    PWConfig.Instance.configFreshMode.getPWDisplayMode(),
                    PWConfig.Instance.configFreshMode.getPWA2Gate());

        }

        lastPointIndex = renderPoints.size() - 1;
        if (lastPointIndex < 0) {
            lastPointIndex = 0;
        }
        return PenDrawPointerResultEnums.NONE;
    }

    @NonNull
    @Override
    public Rect getDirty() {
        return rectOfUpdatePW;
    }


    @Nullable
    @Override
    public IPathCache getPathCache() {
        return null;
    }
}
